Tarea 1

Diego Alejandro Estrada Rivera 165352


In [1]:
class Array:
    "Una clase minima para algebra lineal"    
    def __init__(self, list_of_rows): 
        # obtener dimensiones
        self.data = list_of_rows
        nrow = len(list_of_rows)
        #  ___caso vector: redimensionar correctamente
        if not isinstance(list_of_rows[0], list):
            nrow = 1
            self.data = [[x] for x in list_of_rows]
        # ahora las columnas deben estar bien aunque sea un vector
        ncol = len(self.data[0])
        self.shape = (nrow, ncol)
        # validar tamaño correcto de filas
        if any([len(r) != ncol for r in self.data]):
            raise Exception("Las filas deben ser del mismo tamano")
        # validar que los elementos sean numéricos
        for i in range(nrow):
            for j in range(ncol):
                if not isinstance(self.data[i][j], (int, float, complex)):
                    raise Exception("'" + str(self.data[i][j]) + "'" + " no es numérico")
                                     
# Ejercicio 1

    def __repr__(self):
        if((len(self.data)) == 1):
            return ("Array(" + str(self.data[0]) + ")")
        else:
            cadena = "Array("   
            for i in range(len(self.data)):
                if(i==0):
                    cadena = cadena + str(self.data[i]) + ",\n"
                elif(i>0 and i<(len(self.data)-1)):
                    cadena = cadena + "      " + str(self.data[i]) + ",\n" 
                elif(i == (len(self.data)-1)):
                    cadena = cadena + "      " + str(self.data[i])
            return (cadena + ")")
    
    def __str__(self):
        cadena = ""   
        for i in range(len(self.data)):
            cadena = cadena + str(self.data[i]) + "\n"
        return cadena
    
# Ejercicio 2

    def __getitem__(self, idx):
        return self.data[idx[0]][idx[1]]
    
    
    def __setitem__(self, idx, new_value):
        self.data[idx[0]][idx[1]] = new_value
        
# Ejercicio 3

    def zeros(x, y):
        zeroarray = Array([[0 for c in range(y)] for r in range(x)])
        return zeroarray
        
    def eye(x):
        eyearray = Array([[0 for c in range(x)] for r in range(x)])  
        for i in range(x):
            for j in range(x):
                if i == j:
                    eyearray[i,j] = 1
        return eyearray
    
# Ejercicio 4

    def transpose(self):
        #Obtener dimensiones
        nrow = len(self.data)
        ncol = len(self.data[0])  
        #Crear matriz receptora
        transpuesta = Array([[0 for c in range(nrow)] for r in range(ncol)])
        #Transponer
        for i in range(nrow):
            for j in range(ncol):
                transpuesta[j,i] = self.data[i][j]         
        return transpuesta
    
# Ejercicio 5
       
    def __add__(self, other):
        #Matriz, matriz
        if isinstance(other, Array):
            #Validar las dimensiones
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            #Obtener dimensiones
            rows, cols = self.shape
            #Crear matriz receptora
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            #Sumar
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other.data[r][c]
            return newArray
        #Matriz, entero
        elif isinstance(other, (int, float, complex)): 
            #Obterner dimensiones
            rows, cols = self.shape
            #Crear matriz receptora
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            #Sumar
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] + other
            return newArray
        else:
            return NotImplemented 
               
    __radd__ = __add__
    
    def __sub__(self, other):
        #Matriz, matriz
        if isinstance(other, Array):
            #Validar las dimensiones
            if self.shape != other.shape:
                raise Exception("Las dimensiones son distintas!")
            #Obtener las dimensiones
            rows, cols = self.shape
            #Crear matriz receptora
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            #Restar
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other.data[r][c]
            return newArray
        #Matriz, entero
        elif isinstance(other, (int, float, complex)): 
            #Obtener las dimensiones
            rows, cols = self.shape
            #Crear matriz receptora
            newArray = Array([[0. for c in range(cols)] for r in range(rows)])
            #Restar
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] - other
            return newArray
        else:
            return NotImplemented 
        
# Ejercicio 6
    
    def __mul__(self, other):
        #Matriz, matriz
        if isinstance(other, Array):
            #Validar las dimensiones
            if self.shape[1] != other.shape[0]:
                raise Exception("Las matrices no son compatibles!")
            #Obtener las dimensiones
            rowsA = self.shape[0]
            rowsB = other.shape[0]
            colsB = other.shape[1]
            #Crear matriz receptora
            newArray = Array([[0 for c in range(colsB)] for r in range(rowsA)])
            #Multiplicar
            for i in range(rowsA):
                for j in range(colsB):
                    for k in range(rowsB):
                        newArray[i,j] = newArray[i,j] + self.data[i][k] * other.data[k][j]
            return newArray
        #Matriz, entero
        elif isinstance(other, (int, float, complex)):
            #Obtener las dimensiones
            rows, cols = self.shape
            #Crear matriz receptora
            newArray = Array([[0 for c in range(cols)] for r in range(rows)])
            #Multiplicar
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] * other
            return newArray
        else:
            return NotImplemented
        
    def __rmul__(self, other):
        if isinstance(other, (int, float, complex)):
            rows, cols = self.shape
            newArray = Array([[0 for c in range(cols)] for r in range(rows)])
            for r in range(rows):
                for c in range(cols):
                    newArray.data[r][c] = self.data[r][c] * other
            return newArray
        else:
            return NotImplemented   
        
# Ejericio 7
        
    def foward_sub(self, y):
        #Validar que la matriz sea cuadrada
        if isinstance(self , Array):
            if self.shape[0] != self.shape[1]:
                raise Exception("La matriz no es cuadrada!")
            #Validar que la matriz sea L
            nrow = len(self.data)
            ncol = len(self.data[0])
            for i in range(nrow):
                for j in range(ncol):
                    if(i<j and self.data[i][j] != 0):
                        raise Exception("La matriz no es L!")
            #Validar que no existan ceros en la diagonal
            for i in range(nrow):
                for j in range(ncol):
                    if(i==j and self.data[i][j] == 0):
                        raise Exception("Existen 0's en la diagonal!")
        #Validar que el segundo argumento sea un vector
        if isinstance(y, Array):
            #if not(((y.shape[1]) != 1) or ((y.shape[0]!=1))):
                #raise Exception("El segundo argumento debe ser un vector")
            #Validar que b sea un array columna
            if (y.shape[1] != 1):
                raise Exception("'Ax = b' b tiene que ser un array columna")
            #Validar que b y A tengan el mismo numero de filas
            if (self.shape[0] != y.shape[0]):
                raise Exception("'Ax = b' Las filas del array columna no coinciden con las filas de la matriz")
                
            #Enderezar vector de ser necesario
            #b = y.shape[1]
            #if ((y.shape[1]) == 1 ):
            y = Array.transpose(y)
            #Foward Substitution 
            solution = Array([[0 for n in range(nrow)]])
            for i in range(len(y.data[0])):
                solution[0,i] = y[0,i]
                for j in range(i):
                    solution[0,i] = solution[0,i] - (self[i,j])*(solution[0,j])
                solution[0,i] = ((solution[0,i])/(self[i,i]))
            #Ajustar vector para que salga igual que como entro
            #if (b != 0 ):
            solution = Array.transpose(solution)
            return (solution)
        else:
            return NotImplemented
        
# Ejercicio 8
        
    def backward_sub(self, y):
        #Validar que la matriz sea cuadrada
        if isinstance(self , Array):
            if self.shape[0] != self.shape[1]:
                raise Exception("La matriz no es cuadrada!")
            #Validar que la matriz sea U
            nrow = len(self.data)
            ncol = len(self.data[0])
            for i in range(nrow):
                for j in range(ncol):
                    if(i>j and self.data[i][j] != 0):
                        raise Exception("La matriz no es U!")
            #Validar que no existan ceros en la diagonal
            for i in range(nrow):
                for j in range(ncol):
                    if(i==j and self.data[i][j] == 0):
                        raise Exception("Existen 0's en la diagonal!")
        #Validar que el segundo argumento sea un vector
        if isinstance(y, Array):
            #if not((y.shape[1] == 1) or (y.shape[0]==1)):
                #raise Exception("El segundo argumento debe ser un vector")
            #Validar que b sea un array columna
            if (y.shape[1] != 1):
                raise Exception("'Ax = b' b tiene que ser un array columna")
            #Validar que b y A tengan el mismo numero de filas
            if (self.shape[0] != y.shape[0]):
                raise Exception("'Ax = b' Las filas del array columna no coinciden con las filas de la matriz")
                
            #Enderezar vector de ser necesario
            b = y.shape[1]
            if ((y.shape[1]) == 1 ):
                y = Array.transpose(y)
            #Backward Substitution
            solution = Array([[0 for n in range(nrow)]])
            h = len(y.data[0]) - 1
            m = 0
            for i in range((len(y.data[0])-1),-1,-1):
                solution[0,i] = y[0,i]
                h = len(y.data[0]) - 1
                for j in range(m):
                    solution[0,i] = solution[0,i] - (self[i,h])*(solution[0,h])
                    h-=1
                m += 1
                solution[0,i] = ((solution[0,i])/(self[i,i]))
            #Ajustar vector para que salga igual que como entro
            if (b != 0 ):
                solution = Array.transpose(solution)
            return (solution)
        else:
            return NotImplemented
        
# Ejercicio 9
    
    def lu_decomposition(self): 
        #Validar que la matriz sea cuadrada
        if isinstance(self , Array):
            if self.shape[0] != self.shape[1]:
                raise Exception("La matriz no es cuadrada!")
        #Crear matrices receptroas        
        n = self.shape[1]                                                                                                                                                                                                         
        L = Array.eye(n)
        U = Array.zeros(n,n)       
        P = Array.eye(n)
        # Crear matriz de permutación, con filas en el orden correcto                                                                                                                                                                                                                                                                                                                                                                         
        for o in range(n):
            row = max(range(o, n), key=lambda i: abs(self.data[i][o]))
            if o != row:                                                                                                                                                                                                                            
                P.data[o], P.data[row] = P.data[row], P.data[o]
        #Obtener matriz P*A
        PA = P*self
        # Descomposición LU                                                                                                                                                                                                                     
        for j in range(n):                                                                                                                                                                                                                                                                                                                                                                                            
            for i in range(j+1):
                s1 = sum(U.data[k][j] * L.data[i][k] for k in range(i))
                U.data[i][j] = PA.data[i][j] - s1                                                                                                                                                                
            for i in range(j, n):
                s2 = sum(U.data[k][j] * L.data[i][k] for k in range(j))
                L.data[i][j] = (PA.data[i][j] - s2) / U.data[j][j]
                
        return (P, L, U)
    
# Ejercicio 10
    
    def lu_linsolve(self, b):
        r = self
        e = b
        #Validar que b sea un array columna
        if (e.shape[1] != 1):
            raise Exception("'Ax = b' b tiene que ser un array columna")
        #Validar que b y A tengan el mismo numero de filas
        if (r.shape[0] != e.shape[0]):
            raise Exception("'Ax = b' Las filas del array columna no coinciden con las filas de la matriz")
        P,L,U = Array.lu_decomposition(self)
        if(b.shape[0]==1):
            b = Array.transpose(b)
        b1 = P*b
        y = Array.foward_sub(L,b1)
        x = Array.backward_sub(U,y)
        
        return(x)

In [2]:
A =Array([[1,2,3],[4,5,6],[7,8,9]])

Ejercicio 1


In [3]:
A


Out[3]:
Array([1, 2, 3],
      [4, 5, 6],
      [7, 8, 9])

In [4]:
print(A)


[1, 2, 3]
[4, 5, 6]
[7, 8, 9]

Ejercicio 2


In [5]:
A[0,0] = 3

In [6]:
A


Out[6]:
Array([3, 2, 3],
      [4, 5, 6],
      [7, 8, 9])

In [7]:
A[0,0] = 1

In [8]:
A


Out[8]:
Array([1, 2, 3],
      [4, 5, 6],
      [7, 8, 9])

Ejercicio 3


In [9]:
Array.zeros(2,2)


Out[9]:
Array([0, 0],
      [0, 0])

In [10]:
Array.zeros(5,6)


Out[10]:
Array([0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0],
      [0, 0, 0, 0, 0, 0])

In [11]:
Array.eye(3)


Out[11]:
Array([1, 0, 0],
      [0, 1, 0],
      [0, 0, 1])

In [12]:
Array.eye(5)


Out[12]:
Array([1, 0, 0, 0, 0],
      [0, 1, 0, 0, 0],
      [0, 0, 1, 0, 0],
      [0, 0, 0, 1, 0],
      [0, 0, 0, 0, 1])

Ejercicio 4


In [13]:
A.transpose()


Out[13]:
Array([1, 4, 7],
      [2, 5, 8],
      [3, 6, 9])

In [14]:
Q = Array([[1,2,3],[5,6,7]])

In [15]:
print(Q)


[1, 2, 3]
[5, 6, 7]


In [16]:
print(Q.transpose())


[1, 5]
[2, 6]
[3, 7]

Ejercicio 5


In [17]:
B = Array([[9,8,7],[6,5,4],[3,2,1]])

In [18]:
B


Out[18]:
Array([9, 8, 7],
      [6, 5, 4],
      [3, 2, 1])

In [19]:
A


Out[19]:
Array([1, 2, 3],
      [4, 5, 6],
      [7, 8, 9])

In [20]:
C = A+B

In [21]:
C


Out[21]:
Array([10, 10, 10],
      [10, 10, 10],
      [10, 10, 10])

In [22]:
C+1


Out[22]:
Array([11, 11, 11],
      [11, 11, 11],
      [11, 11, 11])

In [23]:
1+C


Out[23]:
Array([11, 11, 11],
      [11, 11, 11],
      [11, 11, 11])

In [24]:
A-B


Out[24]:
Array([-8, -6, -4],
      [-2, 0, 2],
      [4, 6, 8])

In [25]:
B-A


Out[25]:
Array([8, 6, 4],
      [2, 0, -2],
      [-4, -6, -8])

In [26]:
C-1


Out[26]:
Array([9, 9, 9],
      [9, 9, 9],
      [9, 9, 9])

Ejercicio 6


In [27]:
A*B


Out[27]:
Array([30, 24, 18],
      [84, 69, 54],
      [138, 114, 90])

In [28]:
B*A


Out[28]:
Array([90, 114, 138],
      [54, 69, 84],
      [18, 24, 30])

In [29]:
a= Array([[1,2],[3,4]])

In [30]:
A*a


---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-30-985e0a3770d5> in <module>()
----> 1 A*a

<ipython-input-1-bff5bd34b62a> in __mul__(self, other)
    149             #Validar las dimensiones
    150             if self.shape[1] != other.shape[0]:
--> 151                 raise Exception("Las matrices no son compatibles!")
    152             #Obtener las dimensiones
    153             rowsA = self.shape[0]

Exception: Las matrices no son compatibles!

In [31]:
b= Array([[1,2,3],[4,5,6]])

In [32]:
print(a*b)


[9, 12, 15]
[19, 26, 33]


In [33]:
c = a*b

In [34]:
print(c)


[9, 12, 15]
[19, 26, 33]


In [35]:
print(c*2)


[18, 24, 30]
[38, 52, 66]


In [36]:
print(2*c)


[18, 24, 30]
[38, 52, 66]

Ejercicio 7


In [37]:
F = Array([[3,0,0,0],[-1,1,0,0],[3,-2,-1,0],[1,-2,6,2]])

In [38]:
f = Array([[20],[-7],[4],[3]])

In [39]:
sf=Array.foward_sub(F,f)

In [40]:
print(sf)


[6.666666666666667]
[-0.33333333333333304]
[16.666666666666664]
[-52.16666666666666]


In [41]:
F*sf


Out[41]:
Array([20.0],
      [-7.0],
      [4.0],
      [3.0])

In [42]:
F[0,1] = 1

In [43]:
sf=Array.foward_sub(F,f)


---------------------------------------------------------------------------
Exception                                 Traceback (most recent call last)
<ipython-input-43-ca4c405826d5> in <module>()
----> 1 sf=Array.foward_sub(F,f)

<ipython-input-1-bff5bd34b62a> in foward_sub(self, y)
    200                 for j in range(ncol):
    201                     if(i<j and self.data[i][j] != 0):
--> 202                         raise Exception("La matriz no es L!")
    203             #Validar que no existan ceros en la diagonal
    204             for i in range(nrow):

Exception: La matriz no es L!

Ejercicio 8


In [44]:
B = Array([[4,-1,2,3],[0,-2,7,-4],[0,0,6,5],[0,0,0,3]])

In [45]:
b = Array([[20],[-7],[4],[6]])

In [46]:
sb=Array.backward_sub(B,b)

In [47]:
print(sb)


[3.0]
[-4.0]
[-1.0]
[2.0]


In [48]:
B*sb


Out[48]:
Array([20.0],
      [-7.0],
      [4.0],
      [6.0])

Ejercicio 9


In [49]:
A = Array([[0,-2,3,1],[0,4,-3,2],[1,2,-3,2],[-2,-4,5,-10]])

In [50]:
P,L,U = Array.lu_decomposition(A)

In [51]:
P


Out[51]:
Array([0, 0, 0, 1],
      [0, 1, 0, 0],
      [1, 0, 0, 0],
      [0, 0, 1, 0])

In [52]:
L


Out[52]:
Array([1.0, 0, 0, 0],
      [-0.0, 1.0, 0, 0],
      [-0.0, -0.5, 1.0, 0],
      [-0.5, 0.0, -0.3333333333333333, 1.0])

In [53]:
U


Out[53]:
Array([-2, -4, 5, -10],
      [0, 4.0, -3.0, 2.0],
      [0, 0, 1.5, 2.0],
      [0, 0, 0, -2.333333333333333])

In [54]:
P*A


Out[54]:
Array([-2, -4, 5, -10],
      [0, 4, -3, 2],
      [0, -2, 3, 1],
      [1, 2, -3, 2])

In [55]:
L*U


Out[55]:
Array([-2.0, -4.0, 5.0, -10.0],
      [0.0, 4.0, -3.0, 2.0],
      [0.0, -2.0, 3.0, 1.0],
      [1.0, 2.0, -3.0, 2.0])

Ejercicio 10


In [56]:
y = Array([[6],[1],[0],[5]])

In [57]:
A


Out[57]:
Array([0, -2, 3, 1],
      [0, 4, -3, 2],
      [1, 2, -3, 2],
      [-2, -4, 5, -10])

In [58]:
x = Array.lu_linsolve(A,y)

In [59]:
print(x)


[12.0]
[6.5]
[7.0]
[-2.0]


In [60]:
print(A*x)


[6.0]
[1.0]
[0.0]
[5.0]


In [ ]:


In [ ]: